/**
 * @Author: yzy
 * @Description:
 * @Version: 1.0.0
 * @Date: 2021/12/6 11:14
 * @Copyright: MIN-Group；国家重大科技基础设施——未来网络北大实验室；深圳市信息论与未来网络重点实验室
 */
package router

import (
	"context"
	"errors"
	"fmt"
	"math/rand"
	"minlib/component"
	"minlib/packet"
	"runtime/debug"
	"strings"
	"time"
	"vpn-management-server/logger"
	"vpn-management-server/lru"
	"vpn-management-server/network"
	"vpn-management-server/security/code"
	"vpn-management-server/src/service/ruleservice"
	"vpn-management-server/src/service/userlogservice"
	"vpn-management-server/utils"
)

func StartMINRouter() error {
	var net network.MINNet

	err := net.Listens("/tmp/mir.sock")
	if err != nil {
		logger.Logger.Error("Server Listens failed...")
		return err
	}
	logger.Logger.Info("The min server start success....")
	// 设置监听前缀
	identifier, err := component.CreateIdentifierByString("/mis1/authMsg")
	if err != nil {
		logger.Logger.Error(err)
		return err
	}

	// 向mir注册前缀 设置不过期
	if err := net.RegisterIdentifier(identifier, -1); err != nil {
		logger.Logger.Error(err)
		return err
	}

	// for循环读取包
	for true {
		interest, err := net.ReceiveInterest(-1)
		if err != nil {
			logger.Logger.Error(err)
			return err
		}

		go handleInterest(&net, interest)
	}

	return nil
}

func StartCPacketRouter() error {
	var net network.MINNet

	err := net.Listens("/tmp/mir.sock")
	if err != nil {
		logger.Logger.Error("Server Listens failed...")
		return err
	}

	logger.Logger.Info("The min server start success....")
	// 设置监听前缀
	identifier, err := component.CreateIdentifierByString("/mis1/log/https")
	if err != nil {
		logger.Logger.Error(err)
		return err
	}

	// 向mir注册前缀 设置不过期
	if err := net.RegisterIdentifier(identifier, -1); err != nil {
		logger.Logger.Error(err)
		return err
	}

	// for循环读取包
	for true {
		CPacket, err := net.ReceiveGPPkt(-1)
		if err != nil {
			logger.Logger.Error(err)
			return err
		}

		go handleCPacket(CPacket)
	}

	return nil
}

func handleInterest(net *network.MINNet, interest *packet.Interest) {

	defer func() {
		if err := recover(); err != nil {
			logger.Logger.Error("panic when handleInterest1,err:", err)
			debug.PrintStack()
		}
	}()

	name := interest.GetName()
	uIdentifier, err := name.GetSubIdentifier(3, 1)

	if err != nil {
		logger.Logger.Error(err)
		return
	}

	username := uIdentifier.ToUri()
	username = strings.Trim(username, "/")
	logger.Logger.Debug("username:", username)

	ruleBytes := ruleservice.GetUserRuleByMIN2(username)
	if ruleBytes == nil {
		logger.Logger.Warn("user name is empty")
		return
	}

	resData := packet.Data{}
	resData.SetName(interest.GetName())
	resData.SetTTL(10)
	resData.SetValue(ruleBytes)
	resData.SetNoCache(true)

	if err := net.KeyChain.SignData(&resData); err != nil {
		logger.Logger.Error(err)
		return
	}

	if err := net.SendData(&resData); err != nil {
		logger.Logger.Error(err)
		return
	}
}

func handleCPacket(CPacket *packet.GPPkt) {
	data := CPacket.GetValue()
	userlogservice.UploadUserLogByMIN(data)
}

func StartMINSecRouter() error {

	net := network.MINNet{
		Cache: lru.New(10000, nil),
	}
	// 加密连接监听
	err := net.Listens("/tmp/mir.sock")
	if err != nil {
		logger.Logger.Error("Server Listens failed...")
		return err
	}

	// 设置监听前缀
	identifier, err := component.CreateIdentifierByString("/vms")
	if err != nil {
		logger.Logger.Error(err)
		return err
	}

	// 向mir注册前缀 设置不过期
	if err := net.RegisterIdentifier(identifier, -1); err != nil {
		logger.Logger.Error(err)
		return err
	}
	logger.Logger.Info("The min server start success....")

	return startMIN(&net)

}

func startMIN(net *network.MINNet) error {

	for {
		interest, err := net.ReceiveInterest(-1)
		if err != nil {
			logger.Logger.Error(err)
			return err
		}

		go handleInterest2(net, interest)

	}
}

func handleInterest2(net *network.MINNet, interest *packet.Interest) {
	defer func() {
		if err := recover(); err != nil {
			logger.Logger.Error("panic when handleInterest2,err:", err)
			debug.PrintStack()
		}
	}()

	var length = len(interest.GetName().GetComponents())
	var data *packet.Data
	var err error

	// 如果最后一个片不是分包片 说明是原始请求 那么进行分片 加入缓存中
	if !interest.GetName().GetComponents()[length-1].IsFragmentNumber() {

		respData := getResponseJson(net, interest)
		addDataToCache(net, respData, interest.GetName())
		data = getData(interest.GetName(), utils.IntToBytes(len(respData)))

	} else {
		// 说明是分片请求 那么从缓存中取出数据发送分片包
		dataInter, ok := net.Cache.Get(interest.GetName().ToUri())
		logger.Logger.Warn("interest.GetName().ToUri()", interest.GetName().ToUri())
		if !ok {
			// data = getData(interest.GetName(), []byte(sliceErr.Error()))
			logger.Logger.Error(sliceErr)
			data = getData(interest.GetName(), []byte(sliceErr.Error()))

			err = signAndSendNack(net, interest)
			if err != nil {
				logger.Logger.Error("send nack to vms-proxy fail")
				return
			}

		} else {

			data = dataInter.(*packet.Data)
			logger.Logger.Warn("data.GetName().ToUri()", data.GetName().ToUri())

		}
	}

	if err = signAndSendData(net, data); err != nil {
		logger.Logger.Error("send data to vms-proxy fail")
	} else {
		logger.Logger.Info("send data to vms-proxy success")
	}

}

const (
	MAX_LENGTH = 7000
)

var (
	sliceErr = errors.New("get data slice fail")
)

// getResponseJson 从数据库中取出数据 并加入信息转换成回送的 response json
func getResponseJson(net *network.MINNet, interest *packet.Interest) []byte {
	var resp = network.NewNetResponse()
	var req = network.NewNetRequest()

	req.SetRemote(net.GetRemoteUri())
	// 随机生成一个10位的数字 作为连接ID 生成context字节点 并存储数值key:value
	connID := fmt.Sprintf("%09v", rand.New(rand.NewSource(time.Now().UnixNano())).Int63n(1e10))
	ctx := context.WithValue(context.Background(), "conn_id", connID)

	buf := interest.GetValue()

	logger.Logger.Debug("connID: ", ctx.Value("conn_id").(string), " The Server Received data: ", string(buf))
	// 读取buf解析成结构体 赋值给req
	err := req.SetJsonInfo(buf)
	if err != nil {
		logger.Logger.Error(ctx.Value("conn_id").(string), "Error Unmarshal Json Message, "+string(buf))
		resp.Code = code.BAD_REQUEST
		resp.ErrorMsg = "Error Unmarshal Json Message"
		goto LABLE
	}
	logger.Logger.Debug("parameters:", string(req.Parameters))

	if req.Type == "" {
		logger.Logger.Error(ctx.Value("conn_id").(string), "Error the Request Type is Null, "+string(buf))
		resp.Code = code.BAD_REQUEST
		resp.ErrorMsg = "Error the Request Type is Null"
	} else {
		// 跟据Type 取出对应的 router
		if f, ok := gRouters.typeRouters[req.Type]; !ok {
			logger.Logger.Error(ctx.Value("conn_id").(string), "Not Supported the Request Type, "+string(buf))
			resp.Code = code.BAD_REQUEST
			resp.ErrorMsg = "Not Supported the Request Type"
		} else {
			isCon := true
			if bf, ok := gRouters.beforeRouter[req.Type]; bf != nil && ok {
				isCon = bf(ctx, req, resp)
			} else {
				logger.Logger.Warn("beforeRouter is not registered")
			}

			if isCon == true {
				f(ctx, req, resp)
				if af, ok := gRouters.afterRouter[req.Type]; af != nil && ok {
					af(ctx, req, resp)
				}
			} else {
				logger.Logger.Warn("beforeRouter validate fail")
			}
		}
	}
LABLE:
	return resp.GetJsonInfo()
}

// addDataToCache 发送数据分片
func addDataToCache(net *network.MINNet, dataBytes []byte, name *component.Identifier) {
	var totalLength int = len(dataBytes)
	// 计算分片数量
	var fragmentNum = totalLength/MAX_LENGTH + 1
	// 如果正好整除的话 分片数减一
	if len(dataBytes)%MAX_LENGTH == 0 {
		fragmentNum -= 1
	}

	// 根据分片数量加入对应的分片号 生成新前缀 生成对应的分片数据包
	for i := 0; i < fragmentNum; i++ {
		var data *packet.Data

		// 如果是最后一个分片的话 那么 长度为最后剩余的长度 而不是最大分片长度
		if i < fragmentNum-1 {
			data = getDataSlice(*name, dataBytes[i*MAX_LENGTH:i*MAX_LENGTH+MAX_LENGTH], uint64(i))
		} else {
			data = getDataSlice(*name, dataBytes[i*MAX_LENGTH:], uint64(i))
		}

		// 加入lru缓存
		net.Cache.Add(data.ToUri(), data)
		logger.Logger.Warn("LRU ====> addDataToCache data.ToUri()",data.ToUri())
		logger.Logger.Warn("LRU ====> addDataToCache data.GetName().ToUri()",data.GetName().ToUri())

	}

}

// getDataSlice 获取数据分片
func getDataSlice(identity component.Identifier, dataBytes []byte, fragment uint64) *packet.Data {
	var data packet.Data
	// identity.AppendFragmentNumber(fragment)
	newId, _ := component.CreateIdentifierByComponents(identity.GetComponents())
	newId.AppendFragmentNumber(fragment)

	data.SetName(newId)
	data.SetTTL(10)
	data.SetValue(dataBytes)
	data.SetNoCache(true)

	return &data
}

// getData 获取长度信息数据包
func getData(identity *component.Identifier, msg []byte) *packet.Data {
	var data packet.Data

	data.SetName(identity)
	data.SetTTL(10)
	data.SetValue(msg)
	data.SetNoCache(true)

	return &data
}

// signAndSendData 签名并发送数据包
func signAndSendData(net *network.MINNet, resData *packet.Data) (err error) {
	if err = net.KeyChain.SignData(resData); err != nil {
		logger.Logger.Error(err)
		return
	}

	if err = net.SendData(resData); err != nil {
		logger.Logger.Error(err)
		return
	}

	return
}

// signAndSendNack 签名并发送Nack包
func signAndSendNack(net *network.MINNet, interest *packet.Interest) (err error) {
	if err = net.KeyChain.SignInterest(interest); err != nil {
		logger.Logger.Error(err)
		return
	}

	nack := packet.NewNackByInterest(interest)
	nack.SetNackReason(component.NackReasonNoSlice)
	if err = net.SendNack(nack); err != nil {
		logger.Logger.Error(err)
		return
	}

	return
}
